﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Xsl;
using System.Xml.XPath;
using limpalex.bbparser.Interfaces;

namespace limpalex.bbparser
{
    public class Configuration
    {
        private string _defaultMode;
        private IList<string> _modeNames;
        private readonly IDictionary<string,ParserMode> _modes = new Dictionary<string, ParserMode>();
        private Configuration() {} 

        public static Configuration SampleConfiguration
        {
            get 
            {
                return FromXml(Assembly.GetAssembly(typeof (Configuration)).
                    GetManifestResourceStream("limpalex.config.xml")); 
            }
        }
        
        public static Configuration FromXml(Stream stream)
        {
            var configuration = new Configuration();
            
            var doc = new XmlDocument();
            doc.Load(stream);

            var documentElement = doc.DocumentElement;

            if ( documentElement == null )
                throw new Exception();

            configuration._defaultMode = documentElement.Attributes["default"].Value;
            configuration._modeNames = new List<string>();

            foreach(XmlNode node in documentElement.ChildNodes)
            {
                if (node.NodeType == XmlNodeType.Element)
                    configuration._modeNames.Add(node.Attributes["name"].Value);
            }

            configuration.CheckConfigurations();

            foreach(XmlNode node in documentElement.ChildNodes)
            {
                if (node.NodeType == XmlNodeType.Element)
                {
                    configuration._modes.Add(node.Attributes["name"].Value, ProcessConfigurationElement(node));
                }
            }

            return configuration;
        }

        private static ParserMode ProcessConfigurationElement(XmlNode node)
        {
            TagList tags = null;
            SmileyConfiguration smileys = null;
            ParserOptions options = null;

            foreach (XmlNode child in node.ChildNodes)
            {
                if ( node.NodeType != XmlNodeType.Element )
                    continue;
                switch (child.Name)
                {
                    case "tags":
                        tags = TagList.Create(child);
                        break;
                    case "options":
                        options = ParserOptions.Create(child);
                        break;
                    case "smileys":
                        smileys = SmileyConfiguration.Create(child);
                        break;
                }
            }

            if ( tags == null || options == null || smileys == null )
            {
                throw new Exception();
            }

            return new ParserMode {Options = options, Smileys = smileys, Tags = tags};
        }

        private void CheckConfigurations()
        {
            if (_modeNames.Contains(_defaultMode))
                return;
            throw new Exception();
        }

        public ITextProcessor CreateParser()
        {
            return CreateParser(_defaultMode);
        }

        public ITextProcessor CreateParser(string modeName)
        {
            var mode = _modes[modeName];
            return new Parser(mode.Options, mode.Smileys, mode.Tags);
        }

        public IEnumerable<string> SupportedModes
        {
            get
            {
                foreach(var s in _modeNames)
                {
                    yield return s;
                }
            }
        }

        private struct ParserMode
        {
            public TagList Tags;
            public SmileyConfiguration Smileys;
            public ParserOptions Options;
        }
    }
}
